/**
 * 
 */
package org.nahtanoj.contacts;

import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.logging.Logger;

import org.nahtanoj.driveutils.Authenticator;

import com.google.gdata.client.Query;
import com.google.gdata.client.contacts.ContactsService;
import com.google.gdata.data.contacts.ContactEntry;
import com.google.gdata.data.contacts.ContactFeed;
import com.google.gdata.data.contacts.ContactGroupEntry;
import com.google.gdata.data.contacts.ContactGroupFeed;
import com.google.gdata.data.contacts.GroupMembershipInfo;
import com.google.gdata.util.AuthenticationException;
import com.google.gdata.util.ServiceException;

public class ContactStoreMail implements ContactStore {
	private static final Logger log = Logger.getLogger(ContactStoreMail.class.getName());
	private final ContactsService myService = new ContactsService("CustomSync");
	//	private final HashMap<String, ContactGroup> groups = new HashMap<String, ContactGroup>();
	private final HashMap<String, ContactGroupEntry> groups = new HashMap<String, ContactGroupEntry>();
	//	private final HashMap<String, ContactGroupEntry> systemGroups = new HashMap<String, ContactGroupEntry>();
	private final HashMap<String, Contact> contacts = new HashMap<String, Contact>();
	private ContactGroupEntry myContacts;
	private final HashMap<String, Contact> droppedContacts = new HashMap<String, Contact>();
	private HashMap<String, Contact> matched;
	private HashMap<String, Contact> newDocs;
	private HashMap<String, Contact> newMail;
	private final String user;

	public ContactStoreMail(String u) throws IOException, AuthenticationException {
		//		this.myService = new ContactsService("CustomSync");
		//		Properties p = new Properties();
		//		FileInputStream in = new FileInputStream("passwords.properties");
		//		p.load(in);
		//		in.close();
		//		myService.setUserCredentials(u, p.getProperty(u));
		this.user = u;
		Authenticator a = new Authenticator(u);
		this.myService.setOAuth2Credentials(a.getCredential());
		this.myService.setConnectTimeout(500000);
		this.myService.setReadTimeout(500000);
		this.myService.setProtocolVersion(ContactsService.Versions.V3_1);
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#addContact(org.nahtanoj.contacts.Contact)
	 */
	@Override
	public void add(Contact c) {
		// TODO This is so similar it could be in the new J8 interface default method
		if (c.getHash() == null) {
			c.setHash("a");
		}
		while (contacts.get(c.getHash()) != null) {
			c.setHash(c.getHash() + "a");
		}
		contacts.put(c.getHash(), c);
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#drop(org.nahtanoj.contacts.Contact)
	 */
	@Override
	public void drop(Contact c) {
		String hash = null;
		for (String h : this.contacts.keySet()) {
			if (this.contacts.get(h).equals(c)) {
				if (hash == null) {
					hash = h;
				} else {
					log.warning("Duplicate contact found with same hash:");
				}
			}
		}
		if (hash != null) {
			droppedContacts.put(hash, c);
			this.getContacts().remove(hash);
		} else {
			log.warning("Unable to drop:");
		}
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#getContacts()
	 */
	@Override
	public HashMap<String, Contact> getContacts() {
		return this.contacts;
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#getMatched()
	 */
	@Override
	public HashMap<String, Contact> getMatched() {
		return this.matched;
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#getNewDocs()
	 */
	@Override
	public HashMap<String, Contact> getNewDocs() {
		return this.newDocs;
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#getNewMail()
	 */
	@Override
	public HashMap<String, Contact> getNewMail() {
		return this.newMail;
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#loadContacts()
	 */
	@Override
	public void load() {
		try {
			loadGroups();
			//			for (String g : systemGroups.keySet()) {
			//				System.out.println(g + ":" + systemGroups.get(g).getTitle().getPlainText());
			//			}
			loadContacts();
			//			printAllContacts(myService);
		} catch (IOException e) {
			log.warning("IOException:" + e.getMessage());
		} catch (ServiceException e) {
			log.warning("ServiceException:" + e.getMessage());
		}
	}

	private void loadContacts() throws IOException, ServiceException {
		URL url = new URL("https://www.google.com/m8/feeds/contacts/default/full");
		Query myQuery = new Query(url);
		myQuery.setMaxResults(250);
		myQuery.setStringCustomParameter("group", myContacts.getId());
		ContactFeed resultFeed = myService.query(myQuery, ContactFeed.class);
		for (ContactEntry entry : resultFeed.getEntries()) {
			Contact c = new Contact(entry);
			// TODO can this move to the Contact constructor? - ie add groups from entry reference
			for (GroupMembershipInfo group : entry.getGroupMembershipInfos()) {
				if (groups.get(group.getHref()) != null) {
					c.addGroup(groups.get(group.getHref()).getTitle().getPlainText());
				}
			}
			add(c);
		}
	}

	private void loadGroups() throws IOException, ServiceException {
		URL url = new URL("https://www.google.com/m8/feeds/groups/default/base");
		Query myQuery = new Query(url);
		myQuery.setMaxResults(100);
		ContactGroupFeed resultFeed = myService.query(myQuery, ContactGroupFeed.class);
		for (ContactGroupEntry groupEntry : resultFeed.getEntries()) {
			if (groupEntry.getTitle().getPlainText().equals("System Group: My Contacts")) {
				myContacts = groupEntry;
			} else {
				groups.put(groupEntry.getId(), groupEntry);
			}
		}
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#saveContacts()
	 */
	@Override
	public void save() {
		try {
			FileWriter fw = new FileWriter("CS" + this.user.toUpperCase() + ".csv");
			fw.write("\"Last Name\",\"First Name\",\"Business\",\"Home\",\"Mobile\",\"Mobile 2\",\"E-mail Address\",\"E-mail 2 Address\",\"Home Street\",\"Home Street 2\",\"Home City\",\"Home State\",\"Home Postal Code\",\"Home Country\",\"Birthday\",\"Anniversary\",\"Category\",\"Children\",\"Notes\",\"ContactSync\",\"Hash\",\"Validation\"\n");
			for (Contact c : this.contacts.values()) {
				c.hashUpdate();
				fw.write("\"");
				if (c.getLastName() != null) {		fw.write(c.getLastName()); }		fw.write("\",\"");
				if (c.getFirstName() != null) {		fw.write(c.getFirstName()); }		fw.write("\",\"");
				if (c.getBusiness() != null) {		fw.write(c.getBusiness()); }		fw.write("\",\"");
				if (c.getHome() != null) {			fw.write(c.getHome()); }			fw.write("\",\"");
				if (c.getMobile() != null) {		fw.write(c.getMobile()); }			fw.write("\",\"");
				if (c.getMobile2() != null) {		fw.write(c.getMobile2()); }			fw.write("\",\"");
				if (c.getEmailAddress() != null) {	fw.write(c.getEmailAddress()); }	fw.write("\",\"");
				if (c.getEmail2Address() != null) {	fw.write(c.getEmail2Address()); }	fw.write("\",\"");
				if (c.getHomeStreet() != null) {	fw.write(c.getHomeStreet()); }		fw.write("\",\"");
				if (c.getHomeStreet2() != null) {	fw.write(c.getHomeStreet2()); }		fw.write("\",\"");
				if (c.getHomeCity() != null) {		fw.write(c.getHomeCity()); }		fw.write("\",\"");
				if (c.getHomeState() != null) {		fw.write(c.getHomeState()); }		fw.write("\",\"");
				if (c.getHomePostalCode() != null) {fw.write(c.getHomePostalCode()); }	fw.write("\",\"");
				if (c.getHomeCountry() != null) {	fw.write(c.getHomeCountry()); }		fw.write("\",\"");
				if (c.getBirthday() != null) {		fw.write(c.getBirthday()); }		fw.write("\",\"");
				if (c.getAnniversary() != null) {	fw.write(c.getAnniversary()); }		fw.write("\",\"");
				if (c.getCategory() != null) {		fw.write(c.getCategory()); }		fw.write("\",\"");
				if (c.getChildren() != null) {		fw.write(c.getChildren()); }		fw.write("\",\"");
				if (c.getNotes() != null) {			fw.write(c.getNotes()); }			fw.write("\",\"");
				if (c.getContactSync() != null) {	fw.write(c.getContactSync()); }		fw.write("\",\"");
				if (c.getHash() != null) {			fw.write(c.getHash()); }			fw.write("\",\"");
				if (c.getValidation() != null) {	fw.write(c.getValidation()); }		fw.write("\"\n");
			}
			fw.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/* (non-Javadoc)
	 * @see org.nahtanoj.contacts.ContactStore#setMatches(java.util.HashMap, java.util.HashMap, java.util.HashMap)
	 */
	@Override
	public void setMatches(HashMap<String, Contact> ms,
			HashMap<String, Contact> ud, HashMap<String, Contact> us) {
		this.matched = ms;
		this.newDocs = ud;
		this.newMail = us;
	}

}
